package com.zsqx.dao;

import static org.hibernate.criterion.Example.create;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;

import com.zsqx.tools.PageBean;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Data access object (DAO) for domain model
 * @author MyEclipse Persistence Tools
 */
public class BaseDAO implements IBaseHibernateDAO {
	
	private static final Log log = LogFactory.getLog(BaseDAO.class);
	Session session;
	Transaction tx;
	
	public Session getSession() {
		return HibernateSessionFactory.getSession();
	}
	
	public void save(Object transientInstance) {
		log.debug("saving "+transientInstance.getClass()+" instance");
		session = getSession();
		try {
			tx = session.beginTransaction();
			session.save(transientInstance);
			tx.commit();
			log.debug("save successful");
		} catch (Exception re) {
			log.error("save failed", re);
			re.printStackTrace();
		}finally {
		    session.close();
		}
	}
	public void delete(Object persistentInstance) {
		log.debug("deleting "+persistentInstance.getClass()+" instance");
		session = getSession();
		try {
			tx = session.beginTransaction();
			session.delete(findById(persistentInstance));
			tx.commit();
			log.debug("delete successful");
		} catch (RuntimeException re) {
			log.error("delete failed", re);
			throw re;
		} finally {
		     session.close();
		}
	}
	public void update(Object persistentInstance) {
		log.debug("update "+persistentInstance.getClass()+" instance");
		session = getSession();
		try {
			tx = session.beginTransaction();
			session.update(persistentInstance);
			tx.commit();
			log.debug("update successful");
		} catch (RuntimeException re) {
			log.error("update failed", re);
			throw re;
		} finally {
		    session.close();
		}
	}
	public void saveOrUpdate(Object persistentInstance) {
		log.debug("saveOrUpdate "+persistentInstance.getClass()+" instance");
		session = getSession();
		try {
			tx = session.beginTransaction();
			session.saveOrUpdate(persistentInstance);
			tx.commit();
			log.debug("saveOrUpdate successful");
		} catch (RuntimeException re) {
			log.error("saveOrUpdate failed", re);
			throw re;
		} finally {
		     session.close();
		}
	}
	public Object merge(Object detachedInstance) {
		log.debug("merging "+detachedInstance.getClass()+" instance");
		session = getSession();
		try {
			tx = session.beginTransaction();
			Object result = getSession().merge(detachedInstance);
			tx.commit();
			log.debug("merge successful");
			return result;
		} catch (RuntimeException re) {
			log.error("merge failed", re);
			throw re;
		} finally {
		    session.close();
		}
	}
	public Object findById(Object persistentInstance) {
		Integer id = getObjectId(persistentInstance);
		log.debug("getting "+persistentInstance+" instance with id: " + id);
		session = getSession();
		try {
			Object instance = session.get(persistentInstance.getClass(), id);
			return instance;
		} catch (RuntimeException re) {
			log.error("get failed", re);
			throw re;
		}finally {
			session.clear();
		}
	}
	
	public Integer getAllCount(Object instance){
		session = getSession();
		Criteria criteria = session.createCriteria(instance.getClass());
		criteria.setProjection(Projections.count("id"));
		session.clear();
		return (Integer) criteria.uniqueResult();
	}
	
	public Integer getCount(Criteria criteria){
		criteria.setProjection(Projections.count("id"));
		int count = Integer.parseInt(criteria.list().get(0).toString());
		criteria.setProjection(null);
		return count;
	}
	
	public List findByExample(Object instance) {
		log.debug("finding "+instance.getClass()+" instance by example");
		session = getSession();
		try {
			List<Object> results = (List<Object>) getSession().createCriteria(
					instance.getClass()).add(create(instance)).list();
			log.debug("find by example successful, result size: "
					+ results.size());
			return results;
		} catch (RuntimeException re) {
			log.error("find by example failed", re);
			throw re;
		}finally {
			session.flush();
		}
	}
	
	public Object findOne(Object instance){
		session = getSession();
		List list = findByExample(instance);
		session.flush();
		if(list.size()==0){
			return null;
		}else{
			return list.get(0);
		}
	}
	
	public List findAll(Object bean) {
		String beanName = bean.getClass().getSimpleName();
		log.debug("finding all "+beanName+" instances");
		session = getSession();
		Hibernate.initialize(bean);
		try {
			String queryString = "from "+beanName;
			Query queryObject = session.createQuery(queryString);
			return queryObject.list();
		} catch (RuntimeException re) {
			log.error("find all failed", re);
			throw re;
		} finally {
			session.flush();
		}
	}
	
	public List findByCriteria(Criteria criteria) {
		return criteria.list();
	}

	public List findByPage(Object bean,PageBean pageBean,Criteria criteria){
		session = getSession();
		if(null==criteria){
			criteria = session.createCriteria(bean.getClass());
		}
		criteria.add(create(bean)).setFirstResult(pageBean.getStart()).setMaxResults(pageBean.getPageSize()).addOrder(Order.desc("id"));
		session.flush();
		return criteria.list();
	}
	
	public List findByPage(PageBean pageBean,String sentense,boolean isHQL) {
		session = getSession();
		List list=new ArrayList();
		try {
			if(isHQL){
				Query query=session.createQuery(sentense);
				query.setFirstResult(pageBean.getStart());
				query.setMaxResults(pageBean.getPageSize());
				list=query.list();
			}else{
				SQLQuery sqlQuery=session.createSQLQuery(sentense);
				sqlQuery.setFirstResult(pageBean.getStart());
				sqlQuery.setMaxResults(pageBean.getPageSize());
				list=sqlQuery.list();
			}
		} catch (RuntimeException re) {
			log.error("findByPage failed", re);
			throw re;
		}
		session.flush();
		return list;
	}
	
	/**
	 * 批量删除,传进一堆id格式如 1,2,4
	 * @param bean
	 * @param ids
	 * @return
	 */
	public boolean deleteByBatch(Object bean,String ids) {
		Transaction tc=getSession().beginTransaction();
		tc.begin();
		boolean b = false;
		Connection conn = getSession().connection();
		try {
			String HQL="DELETE FROM "+bean.getClass().getSimpleName()+" WHERE ID IN ("+ids+")";
			System.out.println("Hibernate: "+HQL);
			PreparedStatement pst = conn.prepareStatement(HQL);
			pst.executeUpdate();
			b = true;
			tc.commit();
		} catch (SQLException e) {
			log.error("findByPage failed", e);
			tc.rollback();
			try {
				throw e;
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
		} finally {
			try {
				conn.close();
			} catch (SQLException e) {
				log.error("findByPage failed", e);
				try {
					throw e;
				} catch (SQLException e1) {
					e1.printStackTrace();
				}
			}
		}
		return b;
	}
	public PageBean getPageBean(Integer page, Integer recordCount, Integer pageSize) {
		Integer currentPage = page;
		if(currentPage==null){
			currentPage = 1;
		}
		if(pageSize==null){
			pageSize = PageBean.PAGE_SIZE;
		}
		PageBean pageBean = new PageBean();
		pageBean.setPageSize(pageSize);
		pageBean.setRecordCount(recordCount);
		Integer pageCount = 0;
		if(recordCount%pageSize!=0){
			pageCount = recordCount/pageSize + 1;
		}else {
			pageCount = recordCount/pageSize;
		}
		pageBean.setPageCount(pageCount);
		
		if(currentPage >pageCount){
			currentPage=pageCount;
		}
		if(currentPage<1){
			currentPage=1;
		}
		pageBean.setCurrentPage(currentPage);
		
		int start = (currentPage-1)*pageSize;
		pageBean.setStart(start);
		return pageBean;
	}
	
	public static Integer getObjectId(Object object){
		Class c = object.getClass();
		Integer id = null;
		try {
			Method method = c.getMethod("getId", new Class[] {});
			id = (Integer) method.invoke(object, new Object[] {});
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			log.error("主键不为Id");
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		return id;
	}
}